package com.blockmeta.bbs.businesslibrary.net.retrofit;

import android.annotation.SuppressLint;

import com.blockmeta.bbs.baselibrary.SSLSocketFactoryCompat;
import com.blockmeta.bbs.baselibrary.base.app.BaseApp;
import com.blockmeta.bbs.baselibrary.net.MyPersistentCookieStore;
import com.blockmeta.bbs.baselibrary.net.interceptor.RequestInterceptor;
import com.blockmeta.bbs.baselibrary.net.interceptor.ResponseInterceptor;
import com.blockmeta.bbs.businesslibrary.net.interceptor.AddHeaderInterceptor;
import com.blockmeta.bbs.businesslibrary.net.interceptor.CodeHandleInterceptor;
import com.zhy.http.okhttp.cookie.CookieJarImpl;

import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.cert.Certificate;
import java.security.cert.CertificateFactory;
import java.util.Arrays;
import java.util.Collection;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

import okhttp3.OkHttpClient;

/**
 * @author by author
 * @date 2019/8/7
 * 抽取公共Client
 */
public class BaseOKHttpClient {

    private static BaseOKHttpClient ins;

    public static void invalidateOkHttpClient(){
        ins = null;
    }
    public static BaseOKHttpClient getIns() {

        if (ins == null) {
            return new BaseOKHttpClient();
        }
        return ins;
    }
    public OkHttpClient buildClient(){
        return buildClientTrustAll();
    }
    public OkHttpClient buildClientWithCertificate() {
        // Cookie 持久化
        CookieJarImpl cookieJar = new CookieJarImpl(new MyPersistentCookieStore(BaseApp.getApp()));

        X509TrustManager trustManager;
        SSLSocketFactory sslSocketFactory;
        try {
            trustManager = trustManagerForCertificates(trustedCertificatesInputStream());
            SSLContext sslContext = SSLContext.getInstance("TLS");
            sslContext.init(null, new TrustManager[] { trustManager }, null);
            sslSocketFactory = sslContext.getSocketFactory();
        } catch (GeneralSecurityException e) {
            throw new RuntimeException(e);
        }

        OkHttpClient client = new OkHttpClient.Builder()
                              .cookieJar(cookieJar)
                              .sslSocketFactory(sslSocketFactory, trustManager)
                              .addInterceptor(new AddHeaderInterceptor())
                              .addInterceptor(new CodeHandleInterceptor())
                              .addInterceptor(new ResponseInterceptor())
                              .addInterceptor(new RequestInterceptor())
                              .connectTimeout(10, TimeUnit.SECONDS)
                              .readTimeout(15, TimeUnit.SECONDS)
                              .writeTimeout(15, TimeUnit.SECONDS)
                              .retryOnConnectionFailure(true)
                              .build();
        return client;
    }

    public OkHttpClient buildClientTrustAll() {
        // Cookie 持久化
        CookieJarImpl cookieJar = new CookieJarImpl(new MyPersistentCookieStore(BaseApp.getApp()));

        // 自定义一个信任所有证书的TrustManager
        final X509TrustManager trustAllCert =
                new X509TrustManager() {
                    @SuppressLint("TrustAllX509TrustManager")
                    @Override
                    public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) {
                    }

                    @SuppressLint("TrustAllX509TrustManager")
                    @Override
                    public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType){
                    }

                    @Override
                    public java.security.cert.X509Certificate[] getAcceptedIssuers() {
                        return new java.security.cert.X509Certificate[]{};
                    }
                };
        final SSLSocketFactory sslSocketFactory = new SSLSocketFactoryCompat(trustAllCert);

        OkHttpClient client = new OkHttpClient.Builder()
                .cookieJar(cookieJar)
                .sslSocketFactory(sslSocketFactory, trustAllCert)
                .addInterceptor(new AddHeaderInterceptor())
                .addInterceptor(new CodeHandleInterceptor())
                .addInterceptor(new ResponseInterceptor())
                .addInterceptor(new RequestInterceptor())
                .connectTimeout(10, TimeUnit.SECONDS)
                .readTimeout(15, TimeUnit.SECONDS)
                .writeTimeout(15, TimeUnit.SECONDS)
                .retryOnConnectionFailure(true)
                .build();
        return client;
    }

    private static InputStream trustedCertificatesInputStream(){
        try {
            return BaseApp.getApp().getAssets().open("star_8btc_com.cer");

        } catch (IOException e) {
            e.printStackTrace();
            return null;
        }
    }
    private static X509TrustManager trustManagerForCertificates(InputStream in)
            throws GeneralSecurityException {
        CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509");
        Collection<? extends Certificate> certificates = certificateFactory.generateCertificates(in);
        if (certificates.isEmpty()) {
            throw new IllegalArgumentException("expected non-empty set of trusted certificates");
        }

        // Put the certificates a key store.
        // Any password will work.
        char[] password = "password".toCharArray();
        KeyStore keyStore = newEmptyKeyStore(password);
        int index = 0;
        for (Certificate certificate : certificates) {
            String certificateAlias = Integer.toString(index++);
            keyStore.setCertificateEntry(certificateAlias, certificate);
        }
        // Use it to build an X509 trust manager.
        KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(
                KeyManagerFactory.getDefaultAlgorithm());
        keyManagerFactory.init(keyStore, password);
        TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(
                TrustManagerFactory.getDefaultAlgorithm());
        trustManagerFactory.init(keyStore);
        TrustManager[] trustManagers = trustManagerFactory.getTrustManagers();
        if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) {
            throw new IllegalStateException("Unexpected default trust managers:"
                    + Arrays.toString(trustManagers));
        }
        return (X509TrustManager) trustManagers[0];
    }

    private static KeyStore newEmptyKeyStore(char[] password) throws GeneralSecurityException {
        try {
            KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType());
            /* By convention, 'null' creates an empty key store. */
            InputStream in = null;
            keyStore.load(in, password);
            return keyStore;
        } catch (IOException e) {
            throw new AssertionError(e);
        }
    }
}
